package com.gitee.aop;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.gitee.annotation.AvoidRepeatableCommit;
import com.gitee.exception.OrderException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 重复提交aop
 */
@Aspect
@Component
public class AvoidRepeatableCommitAspect {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Pointcut("@annotation(com.gitee.annotation.AvoidRepeatableCommit)")
    public void pointCut() {
    }

    @Before("pointCut()")
    public void before(JoinPoint joinPoint) {
        ServletRequestAttributes request = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        String ip = request.getRequest().getRemoteAddr();
        //获取注解
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = method.getDeclaringClass().getName();
        String methodName = method.getName();
        int hashCode = String.format("%s#%s", className, methodName).hashCode();
        String redisKey = String.format("%s:%d", ip, hashCode);

//        String lockKey = String.format("%s:%d:%s", ip, hashCode, "lock");
        synchronized (AvoidRepeatableCommitAspect.class) {
            String val = redisTemplate.opsForValue().get(redisKey);
            if (StrUtil.isNotBlank(val)) {
                throw new OrderException(ResponseEnum.AVOID_REPEAT_COMMIT);
            }
            AvoidRepeatableCommit avoidRepeatableCommit =  method.getAnnotation(AvoidRepeatableCommit.class);
            long timeout = avoidRepeatableCommit.timeout();
            redisTemplate.opsForValue().set(redisKey, IdUtil.fastSimpleUUID(), timeout, TimeUnit.MILLISECONDS);
        }
    }
}
